PNDL stands for Place Notation Description Language. The PNDL interpreter emits Place Notation for bell ringing methods on any arbitrary number of bells, within the parameters of the method in question, as defined before interpretation by the quantity 'n'.
PNDL is a one-pass interpreted language, and has a limited number of symbolic commands. The interpreter is completely independent of any software that uses it, and is a separate "DLL" library that can be called from other programs. Use of the PNDL interpretation library "PNDL.dll" is not described further here. Anyone wishing to experiment with it for other purposes is welcome to contact me and I will provide more details.
PNDL is almost completely free-form, in that line-ends and other "white space" characters such as tab stops or spaces are totally ignored. Each command is terminated in either a pre-determined way, for instance by a closing bracket, or in some cases by the start of another command. PNDL itself is terminated by "." or ";".
The structure of a complete piece of PNDL is a Header command, followed by any number of other commands, followed by ".", or ";".
Syntax: @(<Method Name>, <Minimum Stage>, <Maximum Stage>, <Stage Step> ) { | <Stage Information> } }
Contains the method name and information about the stages allowed in the method. Parameters are enclosed in round brackets. There must be at least one set of stage information in this command in order for the complete file to be recognised as valid PNDL. If more than one set of Stage information is included, then each set must be complete, and should represent mutually exclusive options (in most cases this will probably be for odd and even stages.)
- String representing the name of the method, enclosed in double quotes.
Any number of complete sets of information about which stages the method may be used for. Complete sets of stage information are separated by the "|" character. The various parts of the stage information are separated by commas. At least one set of stage information must be present in its entirety for a file to be recognised as valid PNDL. The alternative sets of stage information should be mutually exclusive but this is not checked for. If they are not exclusive, then the first set compatible with the specified stage will be used.
Minimum stage
- minimum number of "bells" on which the method may be rung
Maximum stage
- maximum number of "bells". If there is no maximum stage, this is denoted by '~'
Stage Step Value
- for normally-extending odd or even bell methods, this value will be 2, but could be, say, 4 or more. Can be zero for non-extending methods.
Examples:
@("Plain Bob",4, ~, 2|5,~,2)
@("Cambridge",6, ~, 2)
Syntax: ' <Place Notation> '
Emits Place Notation to the output stream of the PNDL interpreter.
Terminated by a closing single quote.
Anything within the single quotes and not in square brackets is emitted unchanged.
Anything enclosed in square brackets is evaluated before emission. It should be noted that one of 'X', 'x', or '-' is allowed as a "cross change" in Place Notation (this is specifiable in the options for the interpreter), but that PNDL allows any of the three characters as input in the PNDL itself.
Examples:
'12x14'
'[n].1.[n-1].1.'
Syntax: %(<Emit Command>{,<Emit Command>})
Chooses one from a set of Emit commands to be sent to the output stream, depending on the current stage. The command to be used is chosen according to the first Stage Information Set in the Header Command that fits the current stage. Parameters are enclosed in round brackets. There should be as many Emit commands, separated by commas, as sets of Stage Information in the Header command.
Examples:
%('x','1')
%('12','14')
Syntax: \ ( <Command>{<Command>} )
Anything emitted (in an Emit command) within this command is re-emitted in reverse when the matching '/' command is issued.
Parameters are enclosed in round brackets.
Example:
\('[n].1.[n-1].1')
Syntax: \
Anything emitted within a preceding '\' command (Push) is re-emitted in reverse when this command is issued.
Example:
/
Syntax: ! ( <Starting Value>, <End Value>, <Step Value>, <Command> {<Command>} )
Parameters to this command are enclosed by round brackets and separated by commas. While a loop is executing, an index variable is maintained to control the loop. For the first loop, this variable is 'i'. If a second loop is executed within the first, the variable is 'j' for the second loop, and 'k' for a third. It is not expected that deeper loop nesting will be needed, but more variables could easily be added if seriously wanted. Loop variables i, j, and k have a value of zero if referenced outside the loop that they control.
- starting value for the loop index variable
- the loop variable is examined to determine whether it is greater than or equal to (or less than or equal to) the end value. If it is, then the loop terminates. Note that the step value being positive or negative will determine whether a "greater than" or "less than" comparison is made between the value of the index variable and the end value.
- Number by which to increment the index variable after execution of the loop, either positive or negative.
- A series of commands to be executed within the loop. This may be another loop or even include a Push / Pop command pair or comments, but will more usually be a single Emit command.
Example:
!(4, n, 2, '[n].1.[n-2]')
Anything after an opening curly brace and before the terminating closing brace is completely ignored. Comments may be included anywhere that a complete command is expected. Normally this will be as a separate line in the PNDL script, but could be one of the commands in a loop body. Comments are not allowed to be included within the body of a single command.
Example:
{ This is a comment }
There are different conventions for the display of place notation, with minor variations. PNDL attempts to cover most of the major differences:
X', 'x' or '-' means "all bells change".
"&". Some versions of Place Notation include an ampersand to indicate that a section is to be reversed, not including the final change. Others explicitly mention "half leads" and so the ampersand is implicit.
"+" means "Do not reverse this section", but is often omitted.
".". Dots are required notation where places are made in consecutive rows. Some versions of Place Notation omit dots where they are redundant, in other words a dot is not necessary between a change with places made and "x" for "all bells change". For example, in "3.1.3" the dots are required, but in "18.x.18" they may be omitted to give "18x18". Multiple consecutive dots, or dots at the end of a section, are always removed from the emitted output.
External places. By default, all external places ("1" and "[n]") are included explicitly. Some versions of place notation omit the last place, which can always be inferred, and also the first place in cases where it can be inferred (it cannot be inferred if only the first place is made). Options are available in both cases.
By historical convention, bell numbers from 10 to 16 are notated as 0 E T A B C D. A further, but rarer, convention makes another 18 letters available by using the remaining letters of the alphabet, excluding "I", "O", and "X", in alphabetic order up to bell 33. Beyond 33 bells "extended" place notation emits each bell explicitly as a number instead of using letters, but enclosed in curly braces. It is possible to use extended notation for any arbitrary number of bells, including lower numbers where the more conventional notation is normally used. The default is to use "normal" notation for up to and including 33 bells, and extended notation for anything more. There will eventually be options for allowing normal notation up to 16 bells, or to use extended notation only.
Since PNDL was developed to provide a convenient way of producing place notation for use by a computer program, another storage method is used internally by computer programs calling PNDL.dll. All places made are emitted explicitly, and output to a buffer as integers in order. Each row is ended by -1. "x" is denoted by 0 followed by a -1 to denote the end of the row. The whole notation is ended by -2. So, for instance, the place notation for Little Bob at any stage is:
x 1 x 14 x 1 x 12
so this would appear in the internal format as a series of integers being:
0, -1, 1, -1, 0, -1, 1, 4, -1, 0, -1, 1, -1, 0, -1, 1, 2, -1, -2
Place notation may be "simple" or "compound", although PNDL.DLL does not deal with compound notation at the present time. Compound place notation is a series of simple notations separated by commas. This is described in the document:
Thus, the compound notation string &-2-3-4,5 is equivalent to the simple notation string -2-3-4-3-2-5
@("Brampton Surprise", 6, ~, 2) | |
\( | |
' 3[n]x3[n].14x12x36.14x14.' | |
! ( 8, n, 2, '[i-3][i].1[i-2]x1[i-2].' ) | |
) | |
'[n-1][n]' | |
/ | |
'.12' | |
; |
The header shows that the method name is "Brampton Surprise", the minimum stage is 6, there is no maximum stage, and that only even stages are allowed.
The "Push" command contains two commands: an Emit command and a Loop command (that itself contains another Emit command).
The first Loop command uses the control variable 'i' (an internally nested loop would use 'j', and a loop within that would use 'k'). The initial value of 'i' is 8, and looping will continue until 'i' is greater than the stage number 'n' ("greater than" rather than "less than" is indicated by the step value being positive rather than negative). Note that the loop will never be executed with a stage number of 6.
'[n-1][n]' is emitted after the Push command but before the Pop. It therefore represents the "half lead" change. '12' is emitted after the Pop command, and as such is thus the "lead end".
The PNDL is ended by ';' or '.'. PNDL insists on an ending character as an additional check that the PNDL is well-formed.
Thus, for example, the place notation for Brampton Surprise 6, 8, and 10 respectively would be:
36x36.4x2x36.4x4.56.4x4.36x2x4.36x36.2
38x38.4x2x36.4x4.58.6x6.78.6x6.58.4x4.36x2x4.38x38.2
30x30.4x2x36.4x4.58.6x6.70.8x8.90.8x8.70.6x6.58.4x4.36x2x4.30x30.2
@("Plain Bob",4,~,2|5,~,2) | { Here is the "proper" way to do Plain Bob! } | |
{ Allows odd and even stages } | ||
\( | { "Push" command } | |
!(1,n/2-1,1,'x1') | { Loop command } | |
%('x','x1') | { Odd stages use 'x1', even stages use 'x' } | |
) | { End of Push command } | |
%('1','x') | { Half lead | |
/ | { "Pop" command } | |
'12' | { Lead end } | |
. | { Or ';' to end PNDL } |
Noteworthy here is the use of two Stage Information Sets (separated by a '|' character), and the use of Switch commands to choose between them. Multiple Stage Information Sets and use of the Switch command should be seen as advanced use of PNDL and is rarely needed in practice.
Also worthy of note here is the free use of Comment commands, and the use of blank "white space".